<?php 
define ('UI_PAGE_SIZE', 8);
define ('TYPE_IMAGE', '1');
define ('TYPE_MOVIE', '2');
define ('TYPE_RAR', '3');
define ('THREAD_COUNT', 8);
define ('THREAD_FILE', 'thread.db');
define ('ICON_MOVIE', 'images/video_large.png');
define ('ICON_RAR', 'images/rar_large.png');

using ('News_Application_CommandHandler');
using ('News_UI_ControlFactory');
using ('News_Usenet_Server');
using ('News_UI_Articlelist');
using ('News_UI_Image');
using ('News_UI_GroupLoader');
using ('News_UI_Bookmarks');
using ('News_UI_Media');
using ('News_UI_CommandHandler');
using ('News_UI_Downloads');
using ('News_UI_Queue');
using ('News_UI_GroupDialog');
using ('News_Command_AsyncDownloader');
using ('News_Application_CacheManager');
using ('News_Application_MySQLConnection');
using ('News_Application_Thread');
using ('News_Application_ServiceHandler');

class News_Application_Controller
{
    var $Settings;
    var $Server;
    var $viewName;
    var $Imager;
    var $Queue;
    var $Factory;
    var $Jpeg;
    var $Usage;
    var $Async;
    var $Thread;
    function News_Application_Controller()
    {
    	$doc = new DOMDocument('1.0');	     
        set_time_limit  (6000); 
        ini_set("memory_limit","512M");
        $dt = disk_total_space('/');
        $df = disk_free_space('/');
        $this->Usage = (100 - ceil (100 * ($df / $dt))) . '%';
        $this->Settings = array();
        $this->Imager = NULL;
        $this->Async  = new News_Command_AsyncDownloader($this);
        $this->Queue  = new News_UI_Queue($this);
	$this->Thread = new News_Application_Thread($this);
        $this->Jpg    = 'data/progress.jpeg'; 
        $Webservice = new News_Application_ServiceHandler();
    }  
    
    function GetType ($str)
    {
        $picture = preg_match ('/\.(jpg|jpeg|png|gif|bmp)/i', $str);
        $video   = preg_match ('/\.(m4v|flv|mpeg|mpg|mov|wmv|avi|mkv)/i', $str); 
        if (!$video)
        {
            $rar = preg_match ('/\.(rar|r\d{2})/i', $str); 
            if ($rar)
            {
                return TYPE_RAR;
            } 
        }
        return $video ? TYPE_MOVIE : TYPE_IMAGE;
    }
    function SortArticles($result)
    {
        usort($result, 'cmpx');
		return $result;
		
        for($x = 0; $x < sizeof($result); $x++) {
	  for($y = 0; $y < sizeof($result); $y++) {
	    if(strcmp($result[$x]->subject, $result[$y]->subject) < 0) {
	      $hold = $result[$x];
	      $result[$x] = $result[$y];
	      $result[$y] = $hold;
	    }
          }
	}
	return $result;
    }

    function CreateHiLo($low, $high, $size = 8)
    {
    	$div  = $size - 1;
        $ret  = array ($low);
        $span = floor (($high - $low) / $div);
        for ($x=$low + $span;$x<$high&&sizeof($ret)<$div;$x+=$span)
        {
            $ret[] = $x;
        }
        $ret[] = $high - 1;
        return $ret;
    }
    
    function GetSubscribedGroups()
    {    
        $subdata = $this->Read ('data/subdata.txt');
        parse_str($subdata);
        sort ($my);
        return $my;
    }
    
    function Preload ($groupname, $result, $pageindex)
    {
        $this->OpenConnection($groupname); 		
	if ($pageindex > -1)
	{
	    $num = $pageindex * UI_PAGE_SIZE;
	    $min = $num - UI_PAGE_SIZE; 
	}
	else
        {
	    $num = sizeof($result);
	    $min = 0;
	}
	$job = 0;
		 
        for($x=$min;$x<$num&&$x<sizeof($result);$x++)
        { 
            $job ++;
            $id   = $result[$x]->id;
            $name = $result[$x]->subject; 
            $type = $result[$x]->type;
            echo "Job #{$job} {$x}\n------------------------------------\n{$name}\n";
            $this->LogEntry ("$name", $job, UI_PAGE_SIZE, $groupname);
            if ((!isset($type)) || $type=='' || $type=='picture')
            {
                if ($this->GetType($name)==TYPE_IMAGE)
                {
                    echo "{$id}\n"; 
                    $picname = $this->GetArticle ($groupname, $id);
                    echo "{$picname}\n"; 
                }
                else
                {
                    echo "$name is not a picture!\n";
                }
            }
        }
        $this->Imager->Disconnect(); 
    } 

    function LogEncoding ($videofile, $name, $pid = NULL)
    {      

        ob_start();
        passthru("ffmpeg -i \"{$videofile}\" 2>&1");
        $source = ob_get_contents();
        ob_end_clean();

        if (preg_match('/Duration: (.*?),/', $source, $matches))
            $dur = $matches[1];    
            
        $picture = "{$videofile}-temp.jpg";
        $c=("ffmpeg -i \"{$videofile}\" -vcodec mjpeg -vframes 1 -ss 15 -an -f rawvideo -s 320x240 \"{$picture}\"");
        echo $c;
        passthru($c); 
        
        $im      = imagecreatetruecolor (400, 100); 
        $jpeg    = imagecreatefromjpeg($picture);
        $black   = imagecolorallocate ($im, 0, 0, 0);
        $blue    = imagecolorallocate ($im, 99, 99, 255);
        $white   = imagecolorallocate ($im, 255, 255, 255);
        $font    = 'verdana.ttf';
        $array   = explode('/', $videofile);
        $sz=ratio($jpeg, NULL, 100);
        $message = "Name: " . array_pop($array);//. "\nDuration: " . $duration;
        $message2 = "Duration: " . $dur;
        
        imagefill ($im, 0, 0, $white);
        imagecopyresized($im,$jpeg,  0, 0, 0, 0, $sz['x'], $sz['y'], $sz['w'], $sz['h']);
        imagettftext($im,  9, 0, $sz['x'] + 5, 12, $black , $font, $message); 
        imagettftext($im,  9, 0, $sz['x'] + 5, 28, $black , $font, $message2); 
        imagettftext($im,  9, 0, $sz['x'] + 5, 44, $blue , $font, $name); 
        imagettftext($im,  9, 0, $sz['x'] + 5, 60, $black , $font, "Encoding..."); 
        if ($pid)
        {
            imagejpeg ($im, "data/{$pid}.jpeg", 75);
        }
        imagejpeg ($im, $this->Jpg, 75);
        unlink ($picture);
        imagedestroy($im); 
    }

    function LogThread ($message, $value, $max, $group = '', $index = NULL)
    {
    	$my  = array();
    	$old = $this->Read(THREAD_FILE);
		$new = array();
		parse_str($old);
		$my[$index] = "{$message}\t{$value}\t{$max}\t{$group}";
		for ($x=$index-1;$x>-1;$x--) 
		{
			if (!isset($my[$x])) $my[$x] = 'Waiting...';
		}
		for ($x=0;$x<sizeof($my);$x++) 
		{
			$new[] = sprintf('my[%s]=%s', $x, $my[$x]);
		}
		$str = implode ('&', $new);
		$this->Save(THREAD_FILE, $str);
    }
	
	function WriteProgress($im, $data)
	{
        $black   = imagecolorallocate ($im, 0, 0, 0);
        $gray    = imagecolorallocate ($im, 99, 99, 99);
        $blue    = imagecolorallocate ($im, 99, 99, 255);
		$y1      = $data['y1'];
		$y2      = $data['y2'];
		$width   = $data['width'];
		$caption = $data['caption']; 
		$message = $data['message']; 
		$group   = $data['group']; 
		$x       = 20;
		
		$message=str_replace('&amp;', '&',$message);
		$ent=array('/\&amp;/','/\&quot;/','/\&gt;/','/\&lt;/');$ht=array('&','"','>','<');
		$message=preg_replace($ent,$ht,$message);
			
	    imagettftext($im,  9, 0, $x, $y1 - 18, $black , PICTURE_FONT, $message);
        imagettftext($im,  9, 0, $x, $y1 - 4, $black , BUTTON_FONT, $caption);
	    imagettftext($im,  9, 0, $x, $y2 + 14, $black , BUTTON_FONT, $group);
	    
		
		$r = 150;$d=(($y2-$y1)/2);$y3=$y1+$d;$z=floor((255-$r)/$d);
		for ($y=$y1;$y<$y3;$y++)
		{
			$hue   = imagecolorallocate ($im, $r, $r, $r); 
			imageline ($im, $x, $y, 380,$y,$hue);
			$r += $z;
		}
		
        imagefilledrectangle($im, $x, $y1, $width + $x, $y2, $blue);  # progress bar
        
		$r = 99;$z=floor((200-$r)/$d);
		for ($y=$y3;$y<$y2;$y++)
		{
			$hue   = imagecolorallocate ($im, $r, $r, 255); 
			imageline ($im, $x,$y, $width + $x,$y,$hue);
			$r += $z;
		}
        
        
        
        imagerectangle($im, $x, $y1, 380, $y2, $gray);               # progress border
	}

    function LogEntry ($message, $value, $max, $group = '', $index = NULL)
    {
        if ($index !== NULL)
		{
			$this->Thread->Add ($message, $value, $max, $group, $index);
			//$this->LogThread($message, $value, $max, $group, $index);
		}	
		 
		 
		 
        $percent = $value / $max;
        $im      = imagecreate (400, $index!==NULL?400:100);
        $width   = floor (360 * $percent);
        $black   = imagecolorallocate ($im, 0, 0, 0);
        $blue    = imagecolorallocate ($im, 99, 99, 255);
        $white   = imagecolorallocate ($im, 255, 255, 255);
        $font    = 'verdana.ttf';
        $num     = floor($percent * 100) . '%'; 
        
		
        imagefill ($im, 0, 0, $white);
		
		
        $y1      = 40;
        $y2      = 52;
		
		$my = $this->Thread->Read ();
		
		
        //if (file_exists(THREAD_FILE) && $index !== NULL)
        if (sizeof($my) > 0 && $index !== NULL)
		{  
		  //  parse_str($this->Read(THREAD_FILE));
		    $sz = sizeof($my);
		    for ($x=0;$x<$sz;$x++) 
		    {
		    	$y1 += 56;
		    	$y2 += 56;
			    $tmp     = $my[$x]; //explode ("\t", $my[$x]); 
			    
				$message = $tmp['ThreadMessage'];//$tmp[0];
				$value   = $tmp['ThreadValue'];
				$max     = $tmp['ThreadMax'];
				$group   = $x==$sz-1?$tmp['ThreadGroup']:'';
				
				$percent = $value / $max;
                $width   = floor (360 * $percent);
				$num     = floor($percent * 100) . '%'; 
		        $this->WriteProgress($im, array ('y1'      => $y1,
		                                         'y2'      => $y2,
		                                         'width'   => $width,
		                                         'caption' => "{$value} of {$max} - $num",
		                                         'message' => $message,
		                                         'group'   => $group  
		                                         ));
				
		    }
		}
		else {
		    $this->WriteProgress($im, array ('y1'      => $y1,
			                                 'y2'      => $y2,
			                                 'width'   => $width,
			                                 'caption' => "{$value} of {$max} - $num",
			                                 'message' => $message,
			                                 'group'   => $group 
			                                 ));
		} 
		
        imagejpeg ($im, $this->Jpg, 75);
        imagedestroy($im); 
    }
    
    function Save ($path,$data)
    { 
        $fp = fopen($path, 'w');
        if ($fp)
        { 
			if (flock($fp, LOCK_EX)) 
			{ // do an exclusive lock
	            fwrite ($fp, $data);
	            fclose($fp);
			    flock($fp, LOCK_UN); // release the lock
	            return;
			} 
			echo "\n\n *** ERROR: Couldn't get the lock on {$path}!\n";
	    }
        echo "Unable to write to {$path}";
    }

    function Read ($path)
    { 
        $fp = fopen($path, 'r');
        if ($fp)
        {
            if (filesize($path) > 0)
            {
                $fr = fread ($fp, filesize($path));
                fclose($fp);
                return $fr;
            }
        }
        echo "Could not open {$path}";
    }
    
    function Structure ($data)
    {  
        if (!isset($data['onload'])) $data['onload'] = 'attach';
        $fields = array ('header', 'main', 'controlbar', 'toolbar', 'onload');
        $struct = $this->Read('struct.html'); 
        for ($i=0;$i<sizeof($fields);$i++)
        {
            $key = $fields[$i];
            $struct = str_replace ("({$key})", $data[$key], $struct);
        }
        $pattern = "<script language='javascript'>queue.push('%s');</script>\n";
        
        for ($i=0;$i<sizeof($this->Queue->Items);$i++)
        {
            $struct .= sprintf($pattern, $this->Queue->Items[$i]);
        }
        return $struct;
    } 
    
    function Dialog ($data)
    {  
        $fields = array ('RequestURI', 'RedirectURI');
        $struct = $this->Read('signal.html'); 
        for ($i=0;$i<sizeof($fields);$i++)
        {
            $key = $fields[$i];
            $struct = str_replace ("[{$key}]", $data[$key], $struct);
        }
        return $struct;
    }  
    
    function OpenConnection($groupname)
    {
        $this->Settings ['group'] = $groupname;
        $this->Server = new News_Usenet_Server($this);
        $this->Imager = new News_UI_Image($this, false);
        $this->Imager->Connect();
    }
    
    function ReloadGroups()
    {
        $subdata = $this->Read ('data/subdata.txt');
        parse_str($subdata);
        for ($i=0;$i<sizeof($my);$i++)
        {
            $groupname = $my[$i]; 
            $filename   = "data/{$groupname}.xml";
            if (file_exists($filename)) 
            {
	        $xml = simplexml_load_file($filename);
                if ($xml)
                {
                    $result = $xml->xpath("//list/article");
                    $this->Preload ($groupname, $result, 1); 
                } 
            }   
        }  
    }
    
    function CacheName ($dir, $id, $name)
    { 
         $arr = explode ('-', $id);
         $key = $arr[0];
         $this->Save ("{$dir}/{$key}.name", $name);   
    }

    function GetArticle ($group, $id, $dir = NULL, $checkit = true, $omitspaces = true, $prefix = NULL)
    { 
        $b64 = base64_encode ($id);
        $arr = explode ('-', $id);
        $filename = $dir ? "{$dir}/{$b64}" : "data/temp/{$group}/{$b64}"; 
        
        if (file_exists($filename) && !$dir)
        {
            return $filename;
        }
        if (!$checkit)
        {
                $dir = "data/tube/{$group}";
                
                $key = $arr[0];
                $chk = "{$dir}/{$key}.name";
                $idx = "{$dir}/{$key}.idx";
                if (file_exists($chk))
                {
                    return $this->Read ($chk);  
                }
                if (file_exists($idx))
                {
                    $nfo = simplexml_load_file($idx);
                    return $nfo->name;  
                }
        }
        
        $this->Settings ['group'] = $group;
        $this->Settings ['id']    = $id;
        
        // create server and downloader instances 
        if (!$this->Imager)
        {
            $this->Server = new News_Usenet_Server($this);
            $this->Imager = new News_UI_Image($this);
        }
        #echo "Article id #{$id}\n";
//        
        $bsync = $checkit && sizeof ($arr) < 9;
        if ($bsync)
        {
            $articles = $this->Imager->DownloadArticles($id, !$checkit, $prefix);     
            $content  = $this->Imager->Assemble ($articles);
        }
        else
        {
            $content  = $this->Imager->DownloadArticlesEx ($id, $group, THREAD_COUNT, $prefix);
        }
        
        $body  = array();        
        for ($x=0;$x < sizeof($content); $x++)
        { 
		    $body[] = $bsync ? trim($content[$x]['body']) : trim($content[$x]);  
        } 
//        print_r ($body);
        if ($dir || !$checkit)
        {
            $full = $body[0]; 
        
			$fname      = $b64;    
            if (preg_match("/^=ybegin.*name=([^\\r\\n]+)/im", $full, $header))                      
            {                 
				$fname = trim(utf8_encode($header[1]));                  
            }                      
            else if (preg_match ('/begin\s+(\d+)\s+(.*)/im', $full, $header))
            {	    
				$fname = trim(utf8_encode($header[2]));                          
            }    
            $filename = "{$dir}/{$fname}";
            if (!$checkit)
            {   
                if($omitspaces)
                {
                    $fname = str_replace(' ', '--', $fname);
                    $fname = str_replace('#', '--', $fname);
                }
                $dir   = "data/tube/{$group}";
                if (!is_dir($dir)) mkdir ($dir);
                $filename = "{$dir}/{$fname}"; 
            }
        }
        
        if ($this->Imager->Yenc)
        {  
	        $enc  = new yenc($checkit ? NULL : $this);                                                                                                                                                                         
	        $data = $enc->decode($body);   
	        $this->Imager->Save ($filename, $data);  
	        echo filesize ($filename) . " yenc bytes saved\n";
	        return $filename;
        }
        
        if ($this->Imager->Encoding) $encoding = $this->Imager->Encoding;
        
        echo "Encoding {$encoding}\n";
        
	if (strlen($encoding) == 0) $encoding = 'uuencode';
		
		
        $array = array ('header' => array('content-transfer-encoding' => $encoding), 
                        'body'   => implode("\n", $body));   

        $body = $array['body'];
		if (preg_match("/^begin\s+\d{3}\s+(.*)$/im", $body, $header))
		{
            $body = str_replace($header[0], "", $body);   
            $array['body'] = trim($body);
		}     
		
		// if ($encoding=='uuencode')
	       // $this->Imager->Save ("{$id}.uu", $array['body']);  
	    
        $data = decode_message_content($array);
	    $this->Imager->Save ($filename, $data);  
        
	    
	    echo filesize ($filename) . " bytes saved\n";
	    
	    
	    if (!$checkit) return $filename;
	    
	    #echo "Testing image...\n";
	    $im = $this->Imager->ImageCreate ($filename); 
	    if ($im)
	    {
	        imagedestroy($im);
            return $filename;
	    } 
	    
	    echo "Imaging test failed!! Deleting...\n";
	    unlink ($filename); 
	    return NULL; 
    }
    
    function OpenDir ($dir)
    { 
        $array = array();  
        if (is_dir($dir)) {
            if ($dh = opendir($dir)) {
                while (($file = readdir($dh)) !== false) {
                    if (!($file=='.'||$file=='..'))
                    { 
                        $array[] = array('path'=>$dir . $file, 'name'=>$file);
                    }
                }
                closedir($dh);
            }
        }
        return $array;
    }
    
    function URI($array)
    {
        $uri  = explode ('/', $_SERVER['REQUEST_URI']);
        $dict = array();
        $ret  = array();
        for ($i=1;$i<sizeof($uri);$i+=2)
        {
            $dict[ $uri[$i] ] = $uri[ $i + 1 ];
        }
        while (list ($key, $value) = each ($array))
        {  
            $dict[ $key ] = $value;  
        }
		 
        // while (list ($key, $value) = each ($this->Settings))
        // {  
            // $dict[ $key ] = $value;  
        // }
		
        while (list ($key, $value) = each ($dict))
        {  
            if ($value!==NULL)
            {
                $ret[] = "{$key}/{$value}";  
            }
        }
		// reset ($this->Settings);
        return '/' . implode ('/', $ret); 
    }
    
    function AsyncDownload($group, $id, $dir, $thread)
    {  
        $this->Settings ['group'] = $group;
        $this->Server = new News_Usenet_Server($this);
        $this->Imager = new News_UI_Image($this);
        $arr = explode('-', $id);
        $articles = $this->Imager->DownloadArticles($id, NULL, NULL, $dir); 
    }
	
	function MassiveSearch ($group, $param)
	{ 
		  $this->Settings['group'] = $group;
		  $dir   = "data/find/{$group}/";
		  $file  = "{$dir}/{$param}.xml";
		  if (file_exists($file)) return $file;
	  	  if (!is_dir ('data/find')) mkdir ('data/find');
	  	  if (!is_dir ($dir)) mkdir ($dir);
		  
	      $this->Server = new News_Usenet_Server($this); 
		  $xml = $this->Server->SearchThreaded($param);
		  $this->Save($file, $xml);
		  
		  return $file;
	}
     
    function parseUrl()
    {   
         if (is_array( $_SERVER['argv']))
         {
              $arguments = $_SERVER['argv']; 
              if (sizeof($arguments) > 1)
              {
                  if ($arguments[1] == 'v')
                  {
                      $_GET['v'] = $arguments[2];
//                      exit;
                  }
                  else if ($arguments[1]=='g')
                  {
                  	  $this->Settings['group'] = $arguments[2];
                      $this->Server = new News_Usenet_Server($this);
					  $list = new News_UI_Articlelist ($this);
					  $list->Download ();
                      return;
                  }
                  else if ($arguments[1]=='as')
                  {// "php index.php as {$this->groupName} {$param} " . $tmp['x'] . " " . $tmp['y'];
                  	  $group  = $arguments[2];
					  $param  = $arguments[3];
					  $start  = $arguments[4];
					  $end    = $arguments[5]; 
					  $thread = $arguments[6]; 
					  
					  $this->Settings['group'] = $group;
                      $this->Server = new News_Usenet_Server($this); 
					  $file = $this->Server->_SearchNewsGroup ($param, $start, $end, $thread); 
					  
					  echo $file;
                      return;
                  }
                  else if ($arguments[1]=='s')
                  {
                  	  $group = $arguments[2];
					  $param = $arguments[3];
					  $this->Settings['group'] = $group;
					  $dir   = "data/find/{$group}/";
					  $file  = "{$dir}/{$param}.xml";
					  
                  	  if (!is_dir ('data/find')) mkdir ('data/find');
                  	  if (!is_dir ($dir)) mkdir ($dir);
                      $this->Server = new News_Usenet_Server($this); 
					  $xml = $this->Server->SearchNewsGroup($arguments[3]);
					  $this->Save($file, $xml);
					  
					  echo $file;
                      return;
                  }
                  else if ($arguments[1]=='t')
                  { 
                      $this->AsyncDownload($arguments[2], $arguments[3], $arguments[4], $arguments[5]);
                      return;
                  }
                  else if ($arguments[1]=='dl')
                  {
                      $dl = new News_Command_AsyncDownloader($this);
                      $dl->DownloadandProcess($arguments[2], $arguments[3]);
                      return;
                  }
                  else if ($arguments[1]=='r')
                  {
                      $this->ReloadGroups();
                      return;
                  }
                  else
                  {
                      $cli = new News_Application_CommandHandler($this);
                      $cli->Display();
                      return; 
                  }
              }    
         }
         $queryString       = $_GET['v'];  
         $data              = explode ('/',$queryString);#print_r($data);
         $this->viewName    = $data[0];   
         while (list ($key, $value) = each ($_SESSION))
         {  
             $this->Settings[ $key ] = $value;  
         }
         for ($i=1;$i<sizeof($data);$i+=2)
         {
             if (!is_numeric($data[$i]))
             {
                 $this->Settings[ $data[$i] ] = $data[$i + 1]; 
             }
         } 
         while (list ($key, $value) = each ($_POST))
         {  
             $this->Settings[ $key ] = $value;  
         }
        $this->Factory = new News_UI_ControlFactory($this);
        return true;
    } 
    
    function Invoke ()
    {
        if (strlen($this->viewName) > 0)
        {
            $className = 'News_UI_' . ucfirst($this->viewName);
	    if (class_exists($className))
	    {
                try {
	            $ui = new $className($this);
	            $ui->Display();
	            return true;
                } catch (Exception $e) {
                    echo 'Caught exception: ',  $e->getMessage(), "\n";
                    exit;
                }	        
	    } 
        }
        return false;
    }
	
	function GroupRename($str)
	{ 	
        $a=array ('/alt/','/binaries/','/picture/','/erotic/','/nospam/','/multimedia/');
    	$b=array ('a','b','p','e','ns','mm'); 
        return preg_replace($a, $b, $str);  
	}
    
    function Start ()
    {   
        $this->parseUrl();   
        $this->Server = new News_Usenet_Server($this);
        if (!$this->Invoke())
        {
            $this->Server->Display();
        }
    }
}
